#include "RingQueue.hpp"
#include "Task.hpp"
#include <iostream>

// 生产者
void *ProductorRoutine(void *args)
{
    RingQueue<CalTask> *cal_rq = (static_cast<RingQueues<CalTask, SaveTask> *>(args))->_cal_rq;
    while (true)
    {
        int x = rand() % 20;
        int y = rand() % 50;
        const char op = oper[rand() % oper.size()];
        CalTask ct(x, y, op, my_math);
        cal_rq->Push(ct);
        std::cout << "生产者生产任务:" << ct.toString() << " 并传递给消费者完成" << std::endl;
    }
}

// 消费者
void *ConsumerRoutine(void *args)
{
    RingQueue<CalTask> *cal_rq = (static_cast<RingQueues<CalTask, SaveTask> *>(args))->_cal_rq;
    RingQueue<SaveTask> *save_rq = (static_cast<RingQueues<CalTask, SaveTask> *>(args))->_save_rq;

    while (true)
    {
        CalTask ct;
        cal_rq->Pop(&ct);
        std::string result = ct();
        std::cout << "消费者实现任务:" << result << " 实现完成！" << std::endl;
        SaveTask st(result, Save);
        save_rq->Push(st);
        std::cout << "消费者传递任务:" << result << " 给保存者完成！" << std::endl;
    }
}

// 保存者
void *SaverRoutine(void *args)
{
    RingQueue<SaveTask> *save_rq = (static_cast<RingQueues<CalTask, SaveTask> *>(args))->_save_rq;
    while (true)
    {
        SaveTask st;
        save_rq->Pop(&st);
        st();
        std::cout << "保存者保存任务完成！" << std::endl;
    }
}

// 多生产，多消费
void test2()
{
    RingQueues<CalTask, SaveTask> *rqs = new RingQueues<CalTask, SaveTask>();
    rqs->_cal_rq = new RingQueue<CalTask>();
    rqs->_save_rq = new RingQueue<SaveTask>();

    pthread_t p[4], c[8], s;
    for (int i = 0; i < 4; i++)
        pthread_create(p + i, nullptr, ProductorRoutine, rqs);
    for (int i = 0; i < 8; i++)
        pthread_create(c + i, nullptr, ConsumerRoutine, rqs);
    pthread_create(&s, nullptr, SaverRoutine, rqs);

    for (int i = 0; i < 4; i++)
        pthread_join(p[i], nullptr);
    for (int i = 0; i < 8; i++)
        pthread_join(c[i], nullptr);
    pthread_join(s, nullptr);

    delete rqs->_cal_rq;
    delete rqs->_save_rq;
    delete rqs;
}

int main()
{
    srand((unsigned int)time(0) ^ getpid() ^ pthread_self());
    test2();
    return 0;
}